<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>learnES6</title>
</head>

<body>
    <script>
        // let 和 const 声明
        // var 关键字可以变量提升，允许重复声明，允许重复赋值
        // let 关键字具有块级作用域，不允许变量提升，不允许重复声明,但允许重复赋值
        // let a = 1;
        // a = 2;
        // console.log(a);
        // const 关键字声明一个常量，具有块级作用域，不允许变量提升，不允许重复声明，不允许重复赋值
        // const p = 222;
        // console.log(p);




        // 解构赋值
        // 结构数组声明变量
        // let [a, b, c, d] = [1, 2, 3];
        // console.log(a, b, c, d);

        // let [x, [y, z]] = [1, [2, 3]];
        // console.log(x, y, z);

        // let [, , abc] = [1, 2, 3];
        // console.log(abc);

        // 默认值
        // let [aa = true] = [];
        // let [bb = true] = [false];
        // console.log(aa, bb);

        // 结构对象声明对象
        // let { foo, bar } = { foo: 123, bar: 456 };
        // console.log(foo, bar);

        // 字符串的结构赋值
        // const [a, b, c, d, e, f] = 'hello';
        // console.log(a, b, c, d, e, f);
        // 属性结构赋值
        // let { length: len } = 'hello';
        // console.log(len);

        // 函数参数解构赋值
        // function abc([x, y = 3]) {
        //     console.log(x, y);
        // }
        // abc([1]);



        // ***解构赋值用途***
        // 1.交换变量的值
        // let x = 1;
        // let y = 2;
        // [x, y] = [y, x];
        // console.log(x, y);

        // 2.提取JSON数据
        // let jsonData = {
        //     id: 1,
        //     status: 200,
        //     data: [111, 222]
        // };
        // let { id, status, data: number } = jsonData;
        // console.log(id, status, number);


        // 字符的Unicode表示法
        // let haha = '\u0061';
        // console.log(haha);


        // for...of...循环
        // var str = 'hello';
        // for (let i of str) {
        //     console.log(i);
        // }; 

        // 模板字符串
        // let name = 'luo';
        // let age = 18;
        // console.log(`姓名：${name},年龄：${age}`);

        // **字符串新增方法
        // let str = 'luo';
        // **includes(), startsWith(), endsWith() 返回true or false
        // console.log(str.includes('l', 1));
        // console.log(str.startsWith('l'));
        // console.log(str.endsWith('o'));
        // **repeat()
        // console.log(str.repeat(2));
        // padStart(),padEnd()
        // console.log(str.padStart(5, 'abc'));
        // console.log(str.padEnd(5, 'a'));
        // **trim(), trimStart(), trimEnd() 去除字符串首尾空格
        // str = '  luo  ';
        // console.log(str.trim());
        // console.log(str.trimStart());
        // console.log(str.trimEnd());
        // 去除字符串中间空格
        // str = "luo  jianming";
        // console.log(str.replace(/\s/g, ''));
        // console.log(str.replaceAll(' ', ''));


        // 数组扩展
        // ... 展开运算符
        var arr1 = [1, 2, 3];
        var arr2 = [4, 5, 6];
        // concat()合并两数组
        console.log(arr1.concat(arr2));
        console.log([...arr1, ...arr2]);
        console.log(...arr1);

        function plus(...param) {
            console.log(param);
            var total = param.reduce((total, item) => {
                return total + item;
            });
            console.log(total);
        }
        plus(1, 2, 3, 4);

        // Array.from() 方法将类数组对象转化为真实的数组
        // var values = arr1.values();
        // console.log(Array.isArray(values));
        // values = Array.from(values);
        // console.log(values);
        // console.log(Array.isArray(values));
        // Array.of() 方法用于将一组值转换为数组(弥补了Array构造函数的不足)
        // console.log(Array.of(1, 2, 3, 4, 5, 6));
        // copyWithin(target,start=0,end=this.length) 方法将数组内指定位置的元素复制到其他位置
        // var arr = ['luo', 18, 1, 2, 3];
        // console.log(arr.copyWithin(0, 1, 3));
        // find() 返回符合条件的第一个元素的值，没有返回undefined
        // findIndex()  返回符合条件的第一个元素的下标，没有返回-1
        // var res1 = arr.find((n) => {
        //     return n == 'luo';
        // })
        // var res2 = arr.findIndex((n) => {
        //     return n > 2;
        // })
        // console.log(res1, res2);
        // filter() 返回符合条件的所有元素的值
        // var res3 = arr.filter((n) => {
        //     return n > 2;
        // });
        // console.log(res3);
        // map() 返回处理后的数组
        // var res4 = arr.map(value => value * 2);
        // console.log(res4);

        // fill(target,start,end) 方法使用给定值填充一个数组
        // var arr = [1, 2, 3, 4, 5];
        // console.log(arr.fill(6, 1, 3));


        // 箭头函数
        // 1.箭头函数是匿名函数
        // 2.箭头函数没有arguments
        // 3.箭头函数不是对象构造器，不能new
        // 4.箭头函数本身没有this，它拿了上层对象的this，没有的话指向window 
        // var fun = (n) => {
        //     console.log(n);
        // }
        // fun(666);
        // console.log(fun instanceof Function);
        // var obj = {
        //     eat: function () {
        //         console.log(this);
        //     },
        //     say: () => {
        //         console.log(this);
        //     }
        // }
        // obj.eat();
        // obj.say();

        // 对象的扩展
        // 属性的简洁表达方式
        // var name = 'luojianming';
        // var age = 18;
        // var ADD = 'add';
        // var obj = {
        //     name,
        //     age,
        //     [ADD + 'fun']: function () {
        //         console.log('add');
        //     },
        //     fun1: function () {
        //         console.log('fun1');
        //     },
        //     fun2() {
        //         console.log(fun2);
        //     }
        // }
        // console.log(obj.name);
        // console.log(obj.age);
        // obj.addfun();
        // obj.fun1();

        // 对象新增方法
        // Object.is() 与 === 基本一致
        // 不同之处
        // console.log(+0 === -0);
        // console.log(NaN === NaN);
        // console.log(Object.is(+0, -0));
        // console.log(Object.is(NaN, NaN));

        // Set集合 元素唯一
        // var mySet = new Set();
        // mySet.add('luo');
        // mySet.add(18);
        // mySet.add(18);
        // mySet.add(20);
        // mySet.clear();
        // console.log(mySet);
        // console.log(mySet.size);
        // console.log(mySet.has(18));
        // console.log(mySet.keys()); //key和value相同
        // console.log(mySet.values());
        // console.log(mySet.entries());
        // console.log(mySet.delete(18));
        // console.log(mySet);

        // Map对象  key不仅为字符串
        // var myMap = new Map();
        // myMap.set(1, 'luo');
        // myMap.set(null, 18);
        // myMap.set("3", 18);
        // console.log(myMap);
        // console.log(myMap.size);
        // console.log(myMap.get(1));//参数为key
        // console.log(myMap.keys());
        // console.log(myMap.values());
        // console.log(myMap.entries());
        // console.log(myMap.has(1));//参数为key
        // console.log(myMap.delete(1));//参数为key
        // console.log(myMap);
        // myMap.clear();
        // console.log(myMap);




        // js中的类
        // class Person {
        //     constructor(name, age) {
        //         this.name = name;
        //         this.age = age;
        //     }
        //     say() {
        //         console.log("hello");
        //     }
        // }
        // var my = new Person('luo', 18);
        // console.log(my.name);
        // console.log(my.age);
        // console.log(my);
        // my.say();


        // proxy代理
        // var target = {
        //     name: 'luo',
        //     age: 20
        // };
        // var logHandler = {
        //     set: function (target, key, value) {
        //         console.log(`${key}的值被设为了${value}`);
        //         target[key] = value;
        //     },
        //     get: function (target, key) {
        //         if (key == 'name') {
        //             return new Error('禁止读取');
        //         }
        //         console.log(`${key}的值被读取了`);
        //         return target[key];
        //     }
        // }
        // var proxyTarget = new Proxy(target, logHandler);
        // console.log(proxyTarget.name);
        // proxyTarget.age = 18;
        // console.log(proxyTarget.age);


        // Promise对象
        // var myPromise = new Promise(function (resolve, reject) {
        //     setTimeout(() => {
        //         var res = 123456;
        //         resolve(res);
        //     }, 2000);
        // }).then(function (res) {
        //     console.log(res);
        //     return Math.pow(res, 2);
        // }).then(function (res) {
        //     console.log(res);
        // })

        var promise = new Promise(function (resolve, reject) {
            var img = new Image();
            img.src = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1605345515702&di=396678912b7e41df7e84918cdf0fae1e&imgtype=0&src=http%3A%2F%2Fa1.att.hudong.com%2F05%2F00%2F01300000194285122188000535877.jpg";
            img.onload = function () {
                resolve(2222);
            }
            img.onerror = function (err) {
                // reject(err);
                reject(new Error('图片加载出错'));
            }
        })
        // promise.then((img) => {
        //     console.log(promise);
        //     document.body.appendChild(img);
        // }).catch((err) => {
        //     console.log(promise);
        //     console.log(err);
        // })

        // Generator函数
        // function* getData() {
        //     yield 123;
        //     yield 456;
        //     return 789;
        // }
        // var data = getData();
        // console.log(data.next());
        // console.log(data.next());
        // console.log(data.next());
        // console.log(data.next());


        // async函数
        async function go() {
            var res = await promise;
            // console.log(res);
            return res;
        }
        console.log(go());

        // 闭包
        var add = (function () {
            var counter = 0;
            return function () { return counter += 1; }
        })();
        console.log(add());
        console.log(add());
        console.log(add());

        // var xhr = new XMLHttpRequest();
        // xhr.open('get', 'url', 'true');
        // xhr.send();
        // xhr.onreadystatechange = function () {
        //     if (xhr.readyState == 4) {
        //         if (xhr.status == 200) {
        //             var data = xhr.responseText;
        //         }
        //     }
        // }

        // var ajax = new Promise((resolve, reject) => {
        //     var xhr = new XMLHttpRequest();
        //     xhr.open('get', 'http://localhost/PHP&&JS/%E5%B0%9A%E5%AD%A6%E5%A0%82%E7%BB%83%E4%B9%A0/%E6%B1%AA%E8%80%81%E5%B8%88/JS%E5%AD%A6%E4%B9%A0/test2.php?username=luo&password=123456', 'true');
        //     xhr.send();
        //     xhr.onreadystatechange = function () {
        //         if (xhr.readyState == 4) {
        //             if (xhr.status == 200) {
        //                 var data = xhr.responseText;
        //                 resolve(data);
        //             } else {
        //                 reject(xhr.status);
        //             }
        //         }
        //     }
        // });


        // 'http://localhost/PHP&&JS/%E5%B0%9A%E5%AD%A6%E5%A0%82%E7%BB%83%E4%B9%A0/%E6%B1%AA%E8%80%81%E5%B8%88/JS%E5%AD%A6%E4%B9%A0/test2.php?username=luo&password=123456'
        // 用promise封装ajax
        // var $ = {
        //     ajax: function (obj) {
        //         return new Promise((resolve, reject) => {
        //             var xhr = new XMLHttpRequest();
        //             if (obj.type.toLowerCase() == 'get') {
        //                 xhr.open(obj.type, obj.url, 'true');
        //                 xhr.send();
        //             } else if (obj.type.toLowerCase() == 'post') {
        //                 xhr.open(obj.type, obj.url, 'true');
        //                 xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        //                 xhr.send(obj.data)
        //             }
        //             xhr.onreadystatechange = function () {
        //                 if (xhr.readyState == 4) {
        //                     if (xhr.status == 200) {
        //                         var data = xhr.responseText;
        //                         resolve(data);
        //                     } else {
        //                         reject(xhr);
        //                         // reject(xhr.status);
        //                     }
        //                 }
        //             }
        //         })
        //     }
        // }
        // $.ajax({
        //     type: 'post',
        //     url: 'http://localhost/PHP&&JS/%E5%B0%9A%E5%AD%A6%E5%A0%82%E7%BB%83%E4%B9%A0/%E6%B1%AA%E8%80%81%E5%B8%88/JS%E5%AD%A6%E4%B9%A0/test2.php',
        //     data: 'username=luo&password=123456'
        // }).then(function (res) {
        //     res = JSON.parse(res);
        //     console.log(res);
        // }).catch(err => {
        //     console.log(err);
        // }).finally(() => {
        //     console.log('END');
        // })

        // async function login() {
        //     var res = await ajax();
        //     res = JSON.parse(res);
        //     console.log(res);
        // }
        // login();


        // es6方法熟悉一下
        var str = 'jaljflajfld';
        console.log(str.startsWith('j'));
        console.log(str.endsWith('d'));


        // 块级作用域与全局作用域
        var fun = [];
        for (let i = 0; i < 5; i++) {
            fun[i] = function () {
                console.log(i);
            }
        }
        // for (var i = 0; i < 5; i++) {
        //     fun[i] = function () {
        //         console.log(i);
        //     }
        // }
        fun[1]();


        // 广度优先遍历BFS
        function getName2(data) {
            let result = [];
            let queue = data;
            // 队列为空时结束
            while (queue.length > 0) {
                [...queue].forEach(child => {
                    queue.shift();
                    result.push(child.name);
                    child.children && (queue.push(...child.children));
                });
            }
            return result.join(',');
        }
        // 深度优先遍历DFS (递归)
        function getName1(data) {
            const result = [];
            data.forEach(item => {
                const map = data => {
                    result.push(data.name);
                    data.children && data.children.forEach(child => map(child));
                }
                map(item);
            })
            return result.join(',');
        }
        // 深度优先遍历DFS (非递归)
        function getName3(data) {
            const result = [];
            let stack = [];
            for (let i = 0; i < data.length; i++) {
                stack.push(data[i]);
                while (stack.length) {
                    [...stack].forEach(item => {
                        stack.pop();
                        result.push(item.name);
                        if (item.children && item.children.length > 1) {
                            for (let j = 0; j < item.children.length; j++) {
                                stack.push(item.children[j]);
                                item.children[j].children && stack.push(...item.children[j].children);
                            }
                        }
                        // item.children && (stack.push(...(item.children)));
                    })
                }
            }
            return result.join(',');
        }
        const data = [
            {
                name: 'a',
                children: [
                    { name: 'b', children: [{ name: 'e' }] },
                    { name: 'c', children: [{ name: 'f' }] },
                    { name: 'd', children: [{ name: 'g' }] },
                ],
            },
            {
                name: 'a2',
                children: [
                    { name: 'b2', children: [{ name: 'e2' }] },
                    { name: 'c2', children: [{ name: 'f2' }] },
                    { name: 'd2', children: [{ name: 'g2' }] },
                ],
            }
        ]
        console.log(getName3(data));
        console.log(getName1(data));
        console.log(getName2(data));
    </script>
</body>

</html>